package com.info.zhiduoduo.weixin.service;

import com.baomidou.mybatisplus.mapper.Condition;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.info.zhiduoduo.common.configs.CommonConfig;
import com.info.zhiduoduo.common.configs.PayConfig;
import com.info.zhiduoduo.common.configs.ZddUrlConfig;
import com.info.zhiduoduo.common.constants.Constants;
import com.info.zhiduoduo.common.constants.SmartResult;
import com.info.zhiduoduo.common.constants.StatusMsg;
import com.info.zhiduoduo.common.constants.company.CompanyAccountFlowBizType;
import com.info.zhiduoduo.common.constants.maker.MakerBidState;
import com.info.zhiduoduo.common.constants.partner.PartnerStudioWithdrawState;
import com.info.zhiduoduo.common.constants.pay.PayTypeSn;
import com.info.zhiduoduo.common.constants.project.BidType;
import com.info.zhiduoduo.common.constants.project.CalcAmountType;
import com.info.zhiduoduo.common.constants.project.CompanyProjectState;
import com.info.zhiduoduo.common.constants.project.ProjectType;
import com.info.zhiduoduo.common.constants.system.UserType;
import com.info.zhiduoduo.common.exception.Asserts;
import com.info.zhiduoduo.common.exception.SmartException;
import com.info.zhiduoduo.common.formbean.BaseListFormBean;
import com.info.zhiduoduo.common.formbean.BaseSimpleFormBean;
import com.info.zhiduoduo.common.utils.DateUtil;
import com.info.zhiduoduo.common.utils.NumberUtil;
import com.info.zhiduoduo.common.utils.StringUtil;
import com.info.zhiduoduo.core.configs.Redis.RedisKey;
import com.info.zhiduoduo.core.formbean.CalcProjectChargesFormBean;
import com.info.zhiduoduo.core.formbean.ProjectCheckFormBean;
import com.info.zhiduoduo.core.service.*;
import com.info.zhiduoduo.core.service.common.BaseService;
import com.info.zhiduoduo.core.service.common.DocService;
import com.info.zhiduoduo.core.service.common.RedisService;
import com.info.zhiduoduo.repository.dto.crowdsource.ExportProjectAcceptanceDto;
import com.info.zhiduoduo.repository.dto.entrustmentproject.EntrustmentProjectItemDto;
import com.info.zhiduoduo.repository.dto.entrustmentproject.EntrustmentProjectItemReduceDto;
import com.info.zhiduoduo.repository.dto.maker.MakerDetailDto;
import com.info.zhiduoduo.repository.dto.maker.MakerIntroDto;
import com.info.zhiduoduo.repository.dto.maker.MakerZddprojectBidDto;
import com.info.zhiduoduo.repository.dto.maker.StudioDetailDto;
import com.info.zhiduoduo.repository.dto.project.*;
import com.info.zhiduoduo.repository.entity.company.*;
import com.info.zhiduoduo.repository.entity.entrustmentproject.EntrustmentProjectItem;
import com.info.zhiduoduo.repository.entity.maker.MakerBankcard;
import com.info.zhiduoduo.repository.entity.maker.MakerZddProjectBid;
import com.info.zhiduoduo.repository.entity.partner.PartnerBrokerage;
import com.info.zhiduoduo.repository.entity.partner.PartnerStudioWithdraw;
import com.info.zhiduoduo.repository.mapper.company.CompanyPaymentMapper;
import com.info.zhiduoduo.repository.mapper.company.CompanyProjectMapper;
import com.info.zhiduoduo.repository.mapper.crowdsource.CrowdsourceProjectMapper;
import com.info.zhiduoduo.repository.mapper.entrustmentproject.EntrustmentProjectItemMapper;
import com.info.zhiduoduo.repository.mapper.maker.*;
import com.info.zhiduoduo.repository.mapper.system.ProjectCategoryMapper;
import com.info.zhiduoduo.weixin.dto.project.ErrorProjectInfoDto;
import com.info.zhiduoduo.weixin.formbean.company.BatchPublishProjectFormBean;
import com.info.zhiduoduo.weixin.formbean.project.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Transactional
@Service
public class ProjectService extends BaseService {

    @Resource
    CompanyProjectMapper projectMapper;
    @Resource
    CrowdsourceProjectMapper crowdsourceProjectMapper;
    @Resource
    CrowdsourceService crowdsourceService;
    @Resource
    MakerMapper makerMapper;
    @Resource
    MakerStudioMapper makerStudioMapper;
    @Resource
    MakerTagMapper makerTagMapper;
    @Resource
    MakerCaseMapper makerCaseMapper;
    @Resource
    ProjectCategoryMapper projectCategoryMapper;
    @Resource
    CompanyPaymentMapper companyPaymentMapper;
    @Resource
    MakerZddProjectBidMapper makerZddProjectBidMapper;
    @Resource
    EntrustmentProjectItemMapper entrustmentProjectItemMapper;

    @Autowired
    MakerService makerService;
    @Autowired
    CompanyService companyService;
    @Autowired
    WxMessageService wxMessageService;
    @Autowired
    CommonService commonService;
    @Autowired
    CoreProjectService coreProjectService;
    @Autowired
    CoreCompanyService coreCompanyService;
    @Autowired
    ZhiduoduoProjectService zhiduoduoProjectService;
    @Autowired
    CoreLongTermProjectService coreLongTermProjectService;
    @Autowired
    CoreBrokerageService coreBrokerageService;
    @Autowired
    CoreSensitiveService coreSensitiveService;

    @Autowired
    PayConfig payConfig;
    @Autowired
    CommonConfig commonConfig;
    @Autowired
    ZddUrlConfig zddUrlConfig;
    @Autowired
    DocService docService;
    @Resource
    RedisService redisService;

    private ExecutorService executors = Executors.newScheduledThreadPool(1);

    private ExecutorService executorService = Executors.newFixedThreadPool(2);

    public SmartResult<CompanyProjectDto> queryUserProject(BaseSimpleFormBean<QueryProjectFormBean> baseSimpleFormBean) {
        SmartResult smartResult = new SmartResult();

        QueryProjectFormBean reqdata = baseSimpleFormBean.getReqdata();

        int userid = baseSimpleFormBean.getUserid();
        int state = reqdata.getState();
        String name = reqdata.getName();

        Page page = PageHelper.startPage(baseSimpleFormBean.getPage(), baseSimpleFormBean.getRows());

        List<UserProjectDto> infoList = projectMapper.queryProjectForUser(MakerBidState.successBidStates(), userid, name, state);
        smartResult.setList(infoList);

        smartResult.setTotalpages(page.getPages());
        smartResult.setCurrpage(baseSimpleFormBean.getPage());
        smartResult.setTotalrecords(page.getTotal());

        return smartResult;
    }

    public SmartResult<CompanyProjectDto> queryCompanyProject(BaseSimpleFormBean<QueryProjectFormBean> baseSimpleFormBean) {
        SmartResult smartResult = new SmartResult();

        QueryProjectFormBean reqdata = baseSimpleFormBean.getReqdata();

        int userid = baseSimpleFormBean.getUserid();
        int state = reqdata.getState();
        String name = reqdata.getName();

        Page page = PageHelper.startPage(baseSimpleFormBean.getPage(), baseSimpleFormBean.getRows());
        List<CompanyProjectDto> infoList = projectMapper.queryProjectForCompany(userid, name, state);
        smartResult.setList(infoList);

        smartResult.setTotalpages(page.getPages());
        smartResult.setCurrpage(baseSimpleFormBean.getPage());
        smartResult.setTotalrecords(page.getTotal());

        return smartResult;
    }

    public SmartResult<ProjectBriefDto> queryCompanyUserProject(BaseSimpleFormBean<QueryCompanyUserProjectFormBean> formBean) {
        @Valid QueryCompanyUserProjectFormBean reqdata = formBean.getReqdata();
        if (reqdata == null) return errorParamSmartResult();

        int userid = reqdata.getUserid();
        int compid = reqdata.getCompid();
        Page<ProjectBriefDto> page = PageHelper.startPage(formBean.getPage(), formBean.getRows());
        projectMapper.getprojectListByCompidAndUserid(compid, userid);
        return smartResultPage(page);
    }

    public SmartResult queryUserForPublishProject(BaseSimpleFormBean<QueryUserFormBean> baseSimpleFormBean) {
        SmartResult smartResult = new SmartResult();

        QueryUserFormBean queryUserFormBean = baseSimpleFormBean.getReqdata();

        String whereStr = "zu.maker_type = 1 and zu.state = " + Constants.user_state_2;

        if (null != queryUserFormBean && StringUtil.isNotEmpty(queryUserFormBean.getQueryvalue())) {
            whereStr += " and (username like '%" + queryUserFormBean.getQueryvalue() + "%' " + " or phone like '%" + queryUserFormBean.getQueryvalue() + "%' ) and if(ma.opening_location=1, zus.tax_acct_state = 3, 1=1)  ";
        }

        String orderStr = " order by userid desc";

        Page page = PageHelper.startPage(baseSimpleFormBean.getPage(), baseSimpleFormBean.getRows());
        List<UserForPublishProjectDto> infoList = makerMapper.queryUserForPublishProject(whereStr, orderStr);
        smartResult.setList(infoList);

        smartResult.setTotalpages(page.getPages());
        smartResult.setCurrpage(baseSimpleFormBean.getPage());
        smartResult.setTotalrecords(page.getTotal());

        return smartResult;
    }

    /**
     * 批量创建项目草稿，但不发布项目
     */
    public SmartResult batchPublishProject(BaseListFormBean<BatchPublishProjectFormBean> formBean) {
        List<BatchPublishProjectFormBean> reqdata = formBean.getReqdata();
        if (CollectionUtils.isEmpty(reqdata)) return errorParamSmartResult();

        int compid = formBean.getUserid();
        if (compid <= 0) return errorParamSmartResult();
        Company company = new Company().selectById(compid);
        Asserts.notNull(company, StatusMsg.StatusMsg_302);

        //校验敏感词
        List<String> words = Stream.concat(reqdata.stream().map(t -> t.getProjectname()), reqdata.stream().map(t -> t.getProjectintro())).collect(Collectors.toList());
        String checkResult = coreSensitiveService.checkSensitiveWords(words);
        Asserts.isBlank(checkResult, StatusMsg.StatusMsg_143);

        // 校验支付方式
        CompanyParty companyParty = coreCompanyService.getCompanyDefaultPartyZdd(compid);
        Asserts.notNull(companyParty,StatusMsg.StatusMsg_384);

        // 检查如果有合伙人提现申请，不能重复提交 项目
        List<Integer> handledWithdraws = Lists.newArrayList();
        for (BatchPublishProjectFormBean req : reqdata) {
            String partnerWithdrawId = req.getPartnerWithdrawId();
            List<Integer> wdids = StringUtil.splitToInt(partnerWithdrawId, ",");
            List<Integer> handledIds = wdids.stream().filter(wdid -> {
                PartnerStudioWithdraw withdraw = new PartnerStudioWithdraw().selectById(wdid);
                return withdraw.getState() > PartnerStudioWithdrawState.APPLIED;
            }).collect(Collectors.toList());
            if (org.apache.commons.collections.CollectionUtils.isNotEmpty(handledIds)) {
                handledWithdraws.addAll(handledIds);
            }
        }
        if (org.apache.commons.collections.CollectionUtils.isNotEmpty(handledWithdraws)) {
            return SmartResult.fail(StatusMsg.StatusMsg_370).setList(handledWithdraws);
        }

        List<Integer> ids = reqdata.stream().flatMap(projectBean -> {
            int count = projectBean.getCount();
            if (count <= 0) {
                count = 1;
            }
            return Stream.generate(() -> {
                CompanyProject project = new CompanyProject();
                BeanUtils.copyProperties(projectBean, project);

                // 公开竞标项目不需要设置创客信息
                if (projectBean.getBidType() == BidType.INVITATION) {
                    // 邀约项目，设置创客信息
                    int userid = projectBean.getUserid();
                    MakerDetailDto userInfo = makerService.getUserInfo(userid);
                    if (userInfo == null) return null;
                    project.setUsername(userInfo.getUsername()).setRealname(userInfo.getRealname());
                }
                project.setState(CompanyProjectState.DRAFT)
                       .setCompid(compid)
                       .setCompname(company.getCompname())
                       .setCompnickname(company.getCompnickname())
                       .setPartyId(companyParty.getPartyId())
                       .setPayId(companyParty.getPayId());
                // 先预设成交价
                project.setProjectdealamount(projectBean.getProjectamount());

                return project;
            }).limit(count);

        }).map(project -> {
            if (project.insert()) {
                zhiduoduoProjectService.doAfterProjectCreated(project);
                return project.getProjectid();
            } else {
                return null;
            }
        }).filter(Objects::nonNull).collect(Collectors.toList());

        return smartResult(ids);
    }

    /**
     * 编辑草稿
     */
    public SmartResult editProjectDraft(BaseSimpleFormBean<EditProjectDraftFormBean> formBean) {
        EditProjectDraftFormBean reqdata = formBean.getReqdata();
        if (reqdata == null) return errorParamSmartResult();
        int compid = formBean.getUserid();
        Company company = new Company().selectById(compid);
        Asserts.notNull(company, StatusMsg.StatusMsg_302);

        CompanyProject project = new CompanyProject();
        BeanUtils.copyProperties(reqdata, project);

        CompanyParty companyParty = coreCompanyService.getCompanyDefaultPartyZdd(compid);
        Asserts.notNull(companyParty, StatusMsg.StatusMsg_384);

        //校验敏感词
        String checkResult = coreSensitiveService.checkSensitiveWords(project.getProjectname(), project.getProjectintro());
        Asserts.isBlank(checkResult, StatusMsg.StatusMsg_143);

        // 先预设成交价
        project.setPartyId(companyParty.getPartyId())
               .setPayId(companyParty.getPayId())
               .setCompnickname(company.getCompnickname())
               .setProjectdealamount(reqdata.getProjectamount());
        if (reqdata.getUserid() != 0) {
            MakerDetailDto userInfo = makerService.getUserInfo(reqdata.getUserid());
            if (userInfo == null) {
                return errorParamSmartResult();
            }
            //更新用户信息
            project.setUsername(userInfo.getUsername()).setRealname(userInfo.getRealname());
        }

        if (project.updateById()) {
            return smartResult();
        }
        return optFailSmartResult();
    }

    /**
     * 删除草稿
     */
    public SmartResult deleteProjectDraft(BaseSimpleFormBean<String> formBean) {
        String projectids = formBean.getReqdata();
        if (StringUtil.isEmpty(projectids)) return errorParamSmartResult();

        Stream.of(projectids.split(",")).distinct().mapToInt(StringUtil::toInt).forEach(id -> {
            CompanyProject project = new CompanyProject().selectById(id);
            if (CompanyProjectState.isDeletable(project.getState())) {
                project.deleteById();
            }
            zhiduoduoProjectService.doAfterProjectDeletedOrCancelled(project);
        });

        return smartResult();
    }

    /**
     * 提交草稿并直接发布
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public SmartResult submitDraft(BaseSimpleFormBean<SubmitDraftFormBean> formBean) {
        SubmitDraftFormBean reqdata = formBean.getReqdata();
        String projectids = reqdata.getProjectids();
        String payPassword = reqdata.getPayPassword();

        if (StringUtil.isAnyEmpty(projectids, payPassword)) return errorParamSmartResult();

        // 验证支付密码
        int compid = formBean.getUserid();
        // 校验支付密码
        coreCompanyService.checkCompanyPayPassword(compid,payPassword);
        // 支付前校验企业信息
        coreCompanyService.checkCompanyPayBeforeZdd(compid);

        // 获取企业默认支付方式
        CompanyParty companyParty = coreCompanyService.getCompanyDefaultPartyZdd(compid);
        Asserts.notNull(companyParty, StatusMsg.StatusMsg_380);

        // 获取所有项目
        Map<Integer, List<CompanyProject>> bidMap = Stream.of(projectids.split(",")).distinct().mapToInt(StringUtil::toInt).mapToObj(id -> new CompanyProject().selectOne(Condition.create().eq("projectid", id).in("state", Arrays.asList(CompanyProjectState.DRAFT, CompanyProjectState.SUBMIT_FAILED)))).filter(Objects::nonNull).collect(Collectors.groupingBy(CompanyProject::getBidType));

        // 公开招标项目
        List<CompanyProject> bidProjectList = bidMap.get(BidType.PUBLIC);
        // 邀约招标项目
        List<CompanyProject> invitationProjectList = bidMap.get(BidType.INVITATION);

        // 公开招标项目，先提交，不发布，等待竞标
        if (CollectionUtils.isNotEmpty(bidProjectList)) {
            bidProjectList.forEach(p -> p.setState(CompanyProjectState.SUBMITTED).setProjectsubmit(DateUtil.nowTime()).updateById());
        }

        if(CollectionUtils.isNotEmpty(invitationProjectList)) {
            for (CompanyProject project : invitationProjectList) {
                project.setPayId(companyParty.getPayId());
                project.setPartyId(companyParty.getPartyId());
                project.updateById();
            }
        }

        // 其他普通项目，继续原来的流程
        if (org.apache.commons.collections.CollectionUtils.isNotEmpty(invitationProjectList)) {
            List<CompanyProject> list = invitationProjectList;
            // 判断创客是否注销, 已注销的不能发布
            List<CompanyProject> makerErrorList = new ArrayList<>();
            // 天津/芜湖创客还未开税户的,不能交易
            List<CompanyProject> unTaxAcctList = new ArrayList<>();
            // 创客申请注销已受理的，不能发布项目
            List<CompanyProject> rescissionList = new ArrayList<>();
            // 临登创客，不能发布项目
            List<CompanyProject> tempMakerList = new ArrayList<>();
            // 如果企业支付方式是支付宝 创客是否填写支付宝账号
            List<ErrorProjectInfoDto> aliMakerList = new ArrayList<>();

            list.stream().forEach(project -> {
                if (project.getAutoCheck() == 1) {
                    //自动验收判断该时间段不能交易
                    commonService.validRestraintTradeTime(new Date());
                }
                int userid = NumberUtil.safeInt(project.getUserid());
                MakerDetailDto userDetail = makerMapper.getUserState(userid);
                if (userDetail != null) {
                    if (!NumberUtil.equals(userDetail.getState(), Constants.user_state_2)) {
                        makerErrorList.add(project);
                    }
                    // 天津/芜湖创客还未开税户的,不能交易
                    if (NumberUtil.intIn(userDetail.getOpeningLocation(), 1, 3) && !NumberUtil.equals(userDetail.getTaxAcctState(), 3)) {
                        unTaxAcctList.add(project);
                    }
                    // 创客申请注销已受理的，不能发布项目
                    if (NumberUtil.equals(userDetail.getRescissionState(), Constants.user_rescission_state_2)) {
                        rescissionList.add(project);
                    }
                    // 临登创客，不能发布项目
                    if (NumberUtil.equals(userDetail.getTemporaryLogin(), 1)) {
                        tempMakerList.add(project);
                    }
                    // 2022.12.30 增加如果企业支付方式是支付宝 判断创客是否填写支付宝账号
                    if (PayTypeSn.ZFB.equals(companyParty.getPayTypeSn()) && StringUtil.isEmpty(userDetail.getAlipayAccount())) {
                        ErrorProjectInfoDto errorProjectInfoDto = new ErrorProjectInfoDto();
                        errorProjectInfoDto.setProjectId(project.getProjectid());
                        errorProjectInfoDto.setUsername(userDetail.getUsername());
                        errorProjectInfoDto.setRealName(userDetail.getRealname());
                        aliMakerList.add(errorProjectInfoDto);
                    }
                }
            });

            if (!CollectionUtils.isEmpty(makerErrorList)) {
                return SmartResult.fail(StatusMsg.StatusMsg_231).setList(makerErrorList);
            }
            if (!CollectionUtils.isEmpty(unTaxAcctList)) {
                return SmartResult.fail(StatusMsg.StatusMsg_260).setList(unTaxAcctList);
            }
            if (!CollectionUtils.isEmpty(rescissionList)) {
                return SmartResult.fail(StatusMsg.StatusMsg_261).setList(rescissionList);
            }
            if (!CollectionUtils.isEmpty(tempMakerList)) {
                return SmartResult.fail(StatusMsg.StatusMsg_267).setList(tempMakerList);
            }
            if (!CollectionUtils.isEmpty(aliMakerList)) {
                return SmartResult.fail(StatusMsg.StatusMsg_485).setList(aliMakerList);
            }

            //判断有哪些项目的项目款不足以支付服务费和税费
            List<Integer> errorList = list.stream().filter(project -> {
                //计算服务费和税费
                CalcProjectChargesFormBean calcformBean = CalcProjectChargesFormBean.of(project, CalcAmountType.CHECKED);
                CalcProjectChargesDto calcProjectChargesDto = coreProjectService.calcProjectCharge(calcformBean);

                //计算失败，直接报错
                if (calcProjectChargesDto == null || calcProjectChargesDto.getServiceCharge() == null || calcProjectChargesDto.getTaxFee() == null) {
                    return true;
                }

                BigDecimal totalCharges = calcProjectChargesDto.getServiceCharge().add(calcProjectChargesDto.getTaxFee());
                return totalCharges.compareTo(project.getProjectamount()) > 0;

            }).map(CompanyProject::getProjectid).collect(Collectors.toList());
            if (!org.apache.commons.collections.CollectionUtils.isEmpty(errorList)) {
                return smartResult(StatusMsg.StatusMsg_311).setList(errorList);
            }

            // 判断当前余额是否能够支付项目款
            BigDecimal projectAmountSum = list.stream().map(CompanyProject::getProjectamount).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
            SmartResult smartResult = coreProjectService.checkCompanyAccountForProject(compid, companyParty.getPayId(), projectAmountSum);
            if (smartResult.isFailed()) return smartResult;

            // 将所有项目的状态改为发布中
            list.parallelStream().forEach(project -> project.setState(CompanyProjectState.WAIT_SUBMIT).updateById());
            executors.submit(() -> list.forEach(project -> {
                SmartResult publishResult = transact(() -> {
                    //判断当前创客所有进行中，已完成的项目总金额是否已经超过了创客的限额，超过则发布失败
                    coreProjectService.checkMakerQuota(project.getCompid(), project.getUserid(), project.getProjectid(), project.getType(), project.getProjectamount(), CalcAmountType.PROCESSING);

                    // 提交项目
                    project.setPayId(companyParty.getPayId()).setPartyId(companyParty.getPartyId())
                           .setState(CompanyProjectState.SUBMITTED).setProjectsubmit(DateUtil.nowTime()).updateById();
                    SmartResult result = zhiduoduoProjectService.publishProject(project);
                    if (result.isFailed()) {
                        throw SmartException.of(result.getState(), result.getMsg());
                    }
                });

                // 提交草稿，发布失败，记录状态，并记录信息
                if (publishResult.isFailed()) {
                    project.setState(CompanyProjectState.SUBMIT_FAILED).setErrorCode(publishResult.getState()).setErrorMsg(publishResult.getMsg()).updateById();
                }
            }));
        }
        return SmartResult.success();
    }

    public SmartResult publishProject(BaseSimpleFormBean<PublishProjectFormBean> baseSimpleFormBean) {

        PublishProjectFormBean reqdata = baseSimpleFormBean.getReqdata();

        if (reqdata == null) return errorParamSmartResult();

        BigDecimal projectamount = reqdata.getProjectamount();
        if (projectamount == null) return errorParamSmartResult();

        int compid = baseSimpleFormBean.getUserid();
        Company company = new Company().selectById(compid);

        CompanyParty companyParty = coreCompanyService.getCompanyDefaultPartyZdd(compid);
        Asserts.notNull(companyParty,StatusMsg.StatusMsg_384);

        SmartResult smartResult = coreProjectService.checkCompanyAccountForProject(compid, companyParty.getPayId(), projectamount);
        if (smartResult.isFailed()) return smartResult;

        //校验敏感词
        String checkResult = coreSensitiveService.checkSensitiveWords(reqdata.getProjectname(), reqdata.getProjectintro());
        Asserts.isBlank(checkResult, StatusMsg.StatusMsg_143);

        // 创建项目
        CompanyProject project = new CompanyProject();
        BeanUtils.copyProperties(reqdata, project);

        // 公开竞标项目不需要设置创客信息
        if (reqdata.getBidType() == BidType.INVITATION) {
            // 邀约项目，设置创客信息
            int userid = reqdata.getUserid();
            StudioDetailDto makerStudio = makerStudioMapper.getStudioDetail(userid);
            if (makerStudio == null) {
                return smartResult(StatusMsg.StatusMsg_201);
            }
            project.setUsername(makerStudio.getUsername()).setRealname(makerStudio.getRealname());
        }
        // 修改项目信息
        project.setPayId(companyParty.getPayId());
        project.setPartyId(companyParty.getPartyId());
        project.setProjectdealamount(reqdata.getProjectamount());
        project.setType(ProjectType.ZHIDUODUO);
        project.setCompid(compid);
        project.setCompname(company.getCompname());
        project.setCompnickname(company.getCompnickname());
        project.insert();

        // 重新获取项目数据
        project = new CompanyProject().selectById(project.getProjectid());

        //私密且有指定创客的话 ，直接发布
        if (reqdata.getProjecttype() == Constants.projecttype_2 && reqdata.getUserid() > 0) {
            zhiduoduoProjectService.checkProjectAmountBeforePublish(project);
            return zhiduoduoProjectService.publishProject(project);
        }

        return SmartResult.success(project.getProjectid());
    }

    public SmartResult getProjectDetail(BaseSimpleFormBean<ProjectIdFormBean> formBean) {
        ProjectIdFormBean projectIdFormBean = formBean.getReqdata();
        int projectid = projectIdFormBean.getProjectid();
        ProjectDto projectDetail = zhiduoduoProjectService.getProjectDetail(projectid);
        if (formBean.getIdtype() == UserType.MAKER) {
            int userid = formBean.getUserid();
            Integer bid = makerZddProjectBidMapper.isMakerBid(projectid, userid);
            if (bid != null) {
                projectDetail.setBid(bid);
            }
        }

        return SmartResult.success(projectDetail);
    }

    /**
     * 验收项目
     */
    public SmartResult projectCheck(BaseSimpleFormBean<ProjectCheckFormBean> baseSimpleFormBean) {
        //自动验收判断该时间段不能交易
        commonService.validRestraintTradeTime(new Date());
        return zhiduoduoProjectService.checkProject(baseSimpleFormBean.getReqdata());
    }

    public SmartResult userNotifyCheck(BaseSimpleFormBean<UserNotifyCheckFormBean> formBean) {
        UserNotifyCheckFormBean reqdata = formBean.getReqdata();
        int userid = formBean.getUserid();
        if (userid <= 0 || reqdata == null) return errorParamSmartResult();

        int projectid = reqdata.getProjectid();
        CompanyProject project = new CompanyProject().selectById(projectid);

        if (project == null) return smartResult(StatusMsg.StatusMsg_301);
        if (project.getUserid() != userid) return smartResult(StatusMsg.StatusMsg_304);
        if (project.getState() != CompanyProjectState.PROCESSING) return smartResult(StatusMsg.StatusMsg_305);

        boolean update = project.setState(CompanyProjectState.CHECKING).setAttachmentUrl(reqdata.getAttachmentUrl()).setProjectcheckstart(new Date()).updateById();
        if (update) {
            //通知企业
            wxMessageService.notifyCompanyProjectCheck(projectid);
            return smartResult();
        }

        return optFailSmartResult();
    }

    public SmartResult queryUserByField(BaseSimpleFormBean<QueryUserByFieldFormBean> formBean) {
        int userid = formBean.getUserid();
        QueryUserByFieldFormBean reqdata = formBean.getReqdata();
        if (userid <= 0 || reqdata == null) return errorParamSmartResult();

        int fieldid = reqdata.getFieldid();
        String username = reqdata.getUsername();

        Page<Object> page = PageHelper.startPage(formBean.getPage(), formBean.getRows());
        List<MakerIntroDto> list = makerMapper.queryUserByField(username, fieldid);
        list.forEach(dto -> {
            int count = new MakerBankcard().selectCount(Condition.create().eq("userid", dto.getUserid()).eq("accttype", Constants.BANK_ACCT_TYPE_COMPANY).eq("state", 1));
            dto.setBankcardType(count > 0 ? 1 : 0);
            dto.setTagList(makerTagMapper.getUserTagList(dto.getUserid()));
        });

        return smartResult(list, page.getTotal(), page.getPages(), page.getPageNum());
    }

    public SmartResult getUserInfo(BaseSimpleFormBean<Integer> formBean) {

        Integer userid = formBean.getReqdata();

        if (userid == null || userid <= 0) return errorParamSmartResult();

        MakerDetailDto userInfo = makerService.getUserInfo(userid);

        return smartResult(userInfo);
    }

    /**
     * 获取项目分类及模板列表
     */
    public SmartResult getProjectCategoryAndTemplate(BaseSimpleFormBean formBean) {
        List<ProjectCategoryTemplateDto> list = projectCategoryMapper.getProjectCategoryInTemplate();
        list.forEach(category -> category.setTemplateList(projectCategoryMapper.getProjectTemplate(category.getProjectcategoryid())));

        return smartResult(list);
    }

    /**
     * 上传 项目证据链
     *
     * @param formBean formBean
     * @return success
     */
    @Transactional
    public SmartResult uploadProjectFileUrl(BaseSimpleFormBean<UploadProjectFileUrlFormBean> formBean) {
        if (null == formBean || null == formBean.getReqdata() || CollectionUtils.isEmpty(formBean.getReqdata().getProjectIds())) {
            return errorParamSmartResult();
        }
        UploadProjectFileUrlFormBean reqdata = formBean.getReqdata();
        // 项目信息
        List<CompanyProject> companyProjectList = new CompanyProject().selectList(Condition.create().in("projectid", reqdata.getProjectIds()));
        if (CollectionUtils.isEmpty(companyProjectList)) {
            return smartResult(StatusMsg.StatusMsg_301);
        }
        for (CompanyProject companyProject : companyProjectList) {
            companyProject.setAttachmentUrl(reqdata.getProjectFileUrl());
            //保存备注
            companyProject.setRemarksField(reqdata.getRemarksField());
            if (!companyProject.updateById()) {
                throw new SmartException(StatusMsg.StatusMsg_199);
            }
        }
        return smartResult();
    }

    public SmartResult generateProjectDeliveryFile(int compid,GenerateProjectAcceptance acceptance) {
        Company company = new Company().selectById(compid);
        Asserts.notNull(company, StatusMsg.StatusMsg_302);

        List<ExportProjectAcceptanceDto> dtos = docService.generatezddProjectDocDeliverFile(compid, acceptance.getProjectIds());
        Set<String> projectIds = dtos.stream().map(t -> t.getProjectid().toString()).collect(Collectors.toSet());

        if (StringUtils.isNotBlank(acceptance.getProjectIds())) {
            if (CollectionUtils.isEmpty(dtos)) {
                return SmartResult.fail(StatusMsg.StatusMsg_142);
            }
            String[] originalIds = acceptance.getProjectIds().split(",");
            if (projectIds.size() != originalIds.length) {
                Set<String> originalList = new HashSet<>(Arrays.asList(originalIds));
                originalList.removeAll(projectIds);
                return SmartResult.success(originalList);
            }
        }
        return SmartResult.success();
    }

    /**
     * 下载项目生成交付压缩文件
     *
     * @param response
     * @param compid
     * @param projectType
     * @param projectIdList
     */
    public void downloadProjectDeliveryZipFile(HttpServletResponse response, int compid, int projectType, int templateType, List<Integer> projectIdList) {
        if (projectIdList == null || projectIdList.size() <= 0) return;

        if (projectType == ProjectType.ZHIDUODUO) {
            List<ExportProjectAcceptanceDto> list = docService.generatezddProjectDocDeliverFile(compid, StringUtils.join(projectIdList, ","));
            docService.downloadDeliveryProjectDoc(response, list);
        } else {
            Asserts.isTrue(NumberUtil.intIn(templateType, 2, 3));
            List<ExportProjectAcceptanceDto> list = docService.generateCrowdsourceDocDeliverFile(compid, StringUtils.join(projectIdList, ","), templateType, false);
            docService.downloadDeliveryProjectDoc(response, list);
        }
    }

    public SmartResult<UserProjectDto> listProjectBidPoolForUser(BaseSimpleFormBean<ProjectBidPoolFormBean> formBean) {
        ProjectBidPoolFormBean reqdata = formBean.getReqdata();
        // 创客id
        int userid = 0;
        if (formBean.getIdtype() == UserType.MAKER) {
            userid = formBean.getUserid();
        }
        Page<UserProjectDto> page = PageHelper.startPage(formBean.getPage(), formBean.getRows());
        List<UserProjectDto> list = projectMapper.listProjectBidPoolForUser(reqdata.getName(), userid);
        return smartResult(list, page.getTotal(), page.getPages(), page.getPageNum());
    }

    public SmartResult<MakerZddprojectBidDto> listMakerBids(BaseSimpleFormBean<Integer> formBean) {
        Integer projectid = formBean.getReqdata();
        CompanyProject project = projectMapper.selectById(projectid);
        Asserts.notNull(project, StatusMsg.StatusMsg_301);
        List<MakerZddprojectBidDto> list = makerZddProjectBidMapper.listByProjectid(projectid);
        list.forEach(dto -> {
            dto.setCaseList(makerCaseMapper.listByUserid(dto.getUserid()));
            dto.setTagList(makerTagMapper.getUserTagList(dto.getUserid()));
        });
        return SmartResult.success(list);
    }

    public SmartResult bidProject(BaseSimpleFormBean<Integer> formBean) {
        int userid = formBean.getUserid();
        Integer projectid = formBean.getReqdata();
        // 检查竞标的创客是否有效
        MakerDetailDto maker = makerService.getUserInfo(userid);
        Asserts.notNull(maker, StatusMsg.StatusMsg_201);
        CompanyProject project = projectMapper.selectById(projectid);
        Asserts.notNull(project, StatusMsg.StatusMsg_301);
        // 只有公开招标的项目才能创客竞标
        Asserts.isTrue(NumberUtil.equals(project.getBidType(), BidType.PUBLIC), StatusMsg.StatusMsg_363);
        // 项目必须是处于已发布，竞标中或竞标失败的状态下，创客才能参与竞标
        Asserts.isTrue(NumberUtil.intIn(project.getState(), CompanyProjectState.SUBMITTED, CompanyProjectState.BIDDING, CompanyProjectState.BID_FAILED), StatusMsg.StatusMsg_305);

        MakerZddProjectBid projectBid = makerZddProjectBidMapper.getByProjectIdUserid(projectid, userid);
        if (projectBid == null) {
            // 新建创客竞标记录
            projectBid = new MakerZddProjectBid().setProjectId(projectid).setUserid(userid).setBidTime(DateUtil.nowTime()).setState(MakerBidState.BIDDING);
        } else {
            // 判断竞标状态
            Asserts.notEquals(projectBid.getState(), MakerBidState.BIDDING, StatusMsg.StatusMsg_264);
            Asserts.notEquals(projectBid.getState(), MakerBidState.SUCCESS, StatusMsg.StatusMsg_265);
            // 更新竞标信息
            projectBid.setBidTime(DateUtil.nowTime()).setState(MakerBidState.BIDDING);
        }
        project.setState(CompanyProjectState.BIDDING);
        if (project.getBiddingstart() == null) {
            project.setBiddingstart(DateUtil.nowTime());
        }
        if (project.updateById() && projectBid.insertOrUpdate()) {
            // 通知企业
            wxMessageService.notifyCompanyVerifyZddProjectBid(project, projectBid);
        }
        return SmartResult.success();
    }

    public SmartResult verifyMakerBid(BaseSimpleFormBean<VerifyMakerBidFormBean> formBean) {
        VerifyMakerBidFormBean reqdata = formBean.getReqdata();
        int projectid = reqdata.getProjectid();
        int userid = reqdata.getUserid();

        CompanyProject project = projectMapper.selectById(projectid);
        Asserts.notNull(project, StatusMsg.StatusMsg_301);
        // 只有公开招标的项目才能审核创客竞标
        Asserts.isTrue(NumberUtil.equals(project.getBidType(), BidType.PUBLIC), StatusMsg.StatusMsg_363);
        // 只有竞标中的项目才能审核创客竞标
        Asserts.isTrue(NumberUtil.equals(project.getState(), CompanyProjectState.BIDDING), StatusMsg.StatusMsg_305);
        // 检查竞标的创客是否有效
        MakerDetailDto maker = makerService.getUserInfo(userid);
        Asserts.notNull(maker, StatusMsg.StatusMsg_201);
        MakerZddProjectBid projectBid = makerZddProjectBidMapper.getByProjectIdUserid(projectid, userid);
        Asserts.notNull(projectBid, StatusMsg.StatusMsg_266);

        int result = reqdata.getResult();
        if (result == 0) {
            // 拒绝
            projectBid.setState(MakerBidState.VERIFY_FAILED).setVerifyTime(DateUtil.nowTime()).setVerifyRemark(reqdata.getBidRemark()).updateById();
            // 发送消息给创客
            wxMessageService.notifyMakerProjectBidResult(maker, project, projectBid);
            return SmartResult.success();
        } else {
            project.setUserid(userid).setUsername(maker.getUsername()).setRealname(maker.getRealname());
            // 检查项目金额
            zhiduoduoProjectService.checkProjectAmountBeforePublish(project);

            // 更新项目信息
            project.setState(CompanyProjectState.PROCESSING).setBiddingend(DateUtil.nowTime()).updateById();
            // 修改状态，并将竞标同一项目的其他创客都设置为竞标失败
            makerZddProjectBidMapper.failOthers(projectid, userid);
            projectBid.setState(MakerBidState.SUCCESS).setVerifyTime(DateUtil.nowTime()).updateById();
            // 发送消息给创客
            wxMessageService.notifyMakerProjectBidResult(maker, project, projectBid);
            return zhiduoduoProjectService.publishProject(project);
        }
    }

    public SmartResult cancelProject(BaseSimpleFormBean<Integer> formBean) {
        Integer projectid = formBean.getReqdata();
        CompanyProject project = new CompanyProject().selectById(projectid);
        if (project == null) return smartResult(StatusMsg.StatusMsg_301);

        CompanyPayment companyPayment = companyPaymentMapper.getCompanyPayment(project.getCompid(), project.getPayId());
        if (companyPayment == null) return smartResult(StatusMsg.StatusMsg_330);

        // 是可以取消项目的几个状态
        if (CompanyProjectState.isCancelable(project.getState())) {

            BigDecimal projectAmount = project.getProjectamount();
            BigDecimal beforeBalance = companyPayment.getBalance();

            // 非线下项目，并且是需要退款的状态
            if (!PayTypeSn.BTL.equals(companyPayment.getPayTypeSn()) && CompanyProjectState.refundWhileCancelling(project.getState())) {
                //企业账户余额增加退款金额
                BigDecimal currBalance = beforeBalance.add(projectAmount);
                companyPayment.setBalance(currBalance).updateById();

                //生成企业流水账目
                boolean companyFlow = new CompanyAccountflow()
                        .setFlowAmount(projectAmount)
                        .setPayId(companyPayment.getPayId())
                        .setBeforeBalance(beforeBalance)
                        .setCurrBalance(currBalance)
                        .setBeforeFrozenBalance(companyPayment.getFrozenBalance())
                        .setCurrFrozenBalance(companyPayment.getFrozenBalance())
                        .setFlowname(project.getProjectname() + "项目取消").setFlowtype(1)
                        .setBizid(projectid)
                        .setBizType(CompanyAccountFlowBizType.ZDD_PROJECT)
                        .setCompid(project.getCompid())
                        .setPayId(project.getPayId())
                        .insert();
                if (!companyFlow) SmartException.throwOf(StatusMsg.StatusMsg_199);
            }
            // 通用项目修改状态
            if (!project.setState(CompanyProjectState.CANCELLED).updateById()) {
                SmartException.throwOf(StatusMsg.StatusMsg_199);
            }
            // 删除佣金记录
            if (!new PartnerBrokerage().delete(Condition.create().eq("projectid", projectid))) {
                SmartException.throwOf(StatusMsg.StatusMsg_199);
            }

            zhiduoduoProjectService.doAfterProjectDeletedOrCancelled(project);
            return smartResult();
        }

        //不能取消
        return smartResult(StatusMsg.StatusMsg_305);
    }

    /**
     *  发单检测 15分钟内发给同一个人相同金额的返回错误提示
     *
     * @param formBean
     * @return
     */
    public SmartResult checkSameProject(BaseSimpleFormBean<CheckSameProjectFormBean> formBean) {
        CheckSameProjectFormBean reqdata = formBean.getReqdata();
        List<Integer> projectIds = reqdata.getProjectIds();
        // 项目类型
        Integer projectType = reqdata.getProjectType();

        List<SameProjectDto> same = null;
        if (projectType == 1) {
            same = coreProjectService.getTimeSameZddTradeAmount(StringUtils.join(projectIds, ","), formBean.getUserid());
        } else if (projectType == 2) {
            same = coreProjectService.getTimeSameCroTradeAmount(StringUtils.join(projectIds, ","), formBean.getUserid());
        }

        return SmartResult.success(same);
    }

    /**
     * 企业一键生成 /智众包/智零工项目验收单/交付物
     * @param compid
     * @return
     */
    public SmartResult generalAllDelivery(int compid) {
        // 查询 项目
        List<String> zddProjectIds = projectMapper.getCompProjectDeliveryNum(compid, 0);
        List<String> croProjectIds = crowdsourceProjectMapper.getCompProjectDeliveryNum(compid, 1);
        List<String> oddProjectIds = crowdsourceProjectMapper.getCompProjectDeliveryNum(compid, 2);
        List<EntrustmentProjectItemReduceDto> grouponZddProjectIds = entrustmentProjectItemMapper.getCompProjectDeliveryNum(compid,7);
        List<EntrustmentProjectItemReduceDto> grouponCroProjectIds = entrustmentProjectItemMapper.getCompProjectDeliveryNum(compid,8);

        if (CollectionUtils.isEmpty(zddProjectIds) && CollectionUtils.isEmpty(croProjectIds) && CollectionUtils.isEmpty(oddProjectIds)
				&& CollectionUtils.isEmpty(grouponZddProjectIds)
                && CollectionUtils.isEmpty(grouponCroProjectIds)) {
            return smartResult(StatusMsg.StatusMsg_102);
        }

        // 分布式锁，防止重复操作
        String key = RedisKey.genCompGeneralProjectDeliveryKey(compid);
        boolean lock = redisService.getLock(key, UUID.randomUUID().toString(), 180);
        if (!lock) return SmartResult.fail(StatusMsg.StatusMsg_388);

        executorService.execute(() -> {
            try {
                if (!CollectionUtils.isEmpty(zddProjectIds)) {
                    String ids = StringUtils.join(zddProjectIds, ",");
                    GenerateProjectAcceptance acceptance = new GenerateProjectAcceptance();
                    acceptance.setProjectIds(ids);
                    SmartResult smartResult = this.generateProjectDeliveryFile(compid, acceptance);
                    log.info("企业：{},一键生成 项目验收单,项目Ids:{}", compid, ids);
                    if (smartResult.isFailed()) {
                        log.error("企业：{},一键生成 项目验收单失败:{},项目ID:{}", compid, smartResult.getMsg(), ids);
                    }
                }

                if (!CollectionUtils.isEmpty(croProjectIds)) {
                    String ids = StringUtils.join(croProjectIds, ",");
                    GenerateProjectAcceptance acceptance = new GenerateProjectAcceptance();
                    acceptance.setProjectIds(ids);
                    acceptance.setTemplateType(3);
                    SmartResult smartResult = crowdsourceService.generateProjectDeliveryFile(compid, acceptance);
                    log.info("企业：{},一键生成智众包项目验收单,项目Ids:{}", compid, ids);
                    if (smartResult.isFailed()) {
                        log.error("企业：{},一键生成智众包项目验收单失败:{},项目ID:{}", compid, smartResult.getMsg(), ids);
                    }
                }

                if (!CollectionUtils.isEmpty(oddProjectIds)) {
                    String ids = StringUtils.join(oddProjectIds, ",");
                    GenerateProjectAcceptance acceptance = new GenerateProjectAcceptance();
                    acceptance.setProjectIds(ids);
                    acceptance.setTemplateType(3);
                    SmartResult smartResult = crowdsourceService.generateProjectDeliveryFile(compid, acceptance);
                    log.info("企业：{},一键生成智零工项目验收单,项目Ids:{}", compid, ids);
                    if (smartResult.isFailed()) {
                        log.error("企业：{},一键生成智零工项目验收单失败:{},项目ID:{}", compid, smartResult.getMsg(), ids);
                    }
                }

                if (!CollectionUtils.isEmpty(grouponZddProjectIds)) {
                    List<ExportProjectAcceptanceDto> list = docService.generateEntrustZddProjectDocDeliverFile(compid, grouponZddProjectIds);
                    log.info("企业：{},一键生成创客团 项目验收单,项目Ids:{}", compid, grouponZddProjectIds.toString());
                    if (org.springframework.util.CollectionUtils.isEmpty(list)) {
                        log.error("企业：{},一键生成创客团 项目验收单失败,项目ID:{}", compid, grouponZddProjectIds.toString());
                    }
                }

                if (!CollectionUtils.isEmpty(grouponCroProjectIds)) {
                    List<ExportProjectAcceptanceDto> list = docService.generateEntrustCroProjectDocDeliverFile(compid, grouponCroProjectIds, 3);
                    log.info("企业：{},一键生成创客团智众包项目验收单,项目Ids:{}", compid, grouponCroProjectIds.toString());
                    if (org.springframework.util.CollectionUtils.isEmpty(list)) {
                        log.error("企业：{},一键生成创客团智众包项目验收单失败,项目ID:{}", compid, grouponCroProjectIds.toString());
                    }
                }

            } catch (Exception e) {
                log.error("function:generalAllDelivery Exception:{},compid:{}", e, compid);
            } finally {
                // 释放分布式锁
                redisService.releaseLock(key);
            }
        });

        return smartResult();
    }
}
